#ifndef _CLOCK_H_
#define _CLOCK_H_

#include <sel4/sel4.h>

/*
 * Return codes for driver functions
 */
#define CLOCK_R_OK     0        /* success */
#define CLOCK_R_UINT (-1)       /* driver not initialised */
#define CLOCK_R_CNCL (-2)       /* operation cancelled (driver stopped) */
#define CLOCK_R_FAIL (-3)       /* operation failed for other reason */

typedef int64_t timestamp_t;

//content of memory-mapped timers registers from NSLU2_OSTS_PHYS_BASE
#define OST_TS (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x0))
#define OST_TIM0 (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x4))
#define OST_TIM0_RL (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x8))
#define OST_TIM1 (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0xC))
#define OST_TIM1_RL (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x10))
#define OST_WDOG (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x14))
#define OST_WDOG_ENAB (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x18))
#define OST_WDOG_KEY (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x1C))
#define OST_STATUS (*(volatile unsigned long*)(NSLU2_OSTS_VIR_BASE+ 0x20))

#define WDOG_KEY 0x482E

#define NSLU2_OSTS_VIR_BASE 0x20000000

//max number of threads allowed to be queued at a time
#define MAX_TIMERS 1023


//minimum of the interval between timer interrupt : 100us
#define TS_MIN_INT_PERIOD_US 100
//maximum : 100ms
#define TS_MAX_INT_PERIOD_US 1000000



/*
 * Initialise driver. Performs implicit stop_timer() if already initialised.
 *    bi:       seL4 boot information and capabilities
 *
 * Returns CLOCK_R_OK iff successful.
 */
int start_timer(const seL4_BootInfo* bi, seL4_CPtr interrupt_ep);

/*
 * Register a client thread to be woken up by an IPC.
 *    delay:  Delay time in microseconds before sending a reply IPC to client.
 *    client: Client id.
 *
 * Returns CLOCK_R_OK iff successful.
 */
int register_timer(uint64_t delay, seL4_CPtr client);

/*
 * Returns present time in microseconds since booting.
 *
 * Returns a negative value if failure.
 */
timestamp_t time_stamp(void);

/*
 * Stop clock driver operation.
 *
 * Returns CLOCK_R_OK iff successful.
 */
int stop_timer(void);

void clock_interrupts(int irq);

#endif /* _CLOCK_H_ */
